package dk.dtu.is.jjmvcp.view;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;

import dk.dtu.is.jjmvcp.controller.MyController;
import dk.dtu.is.jjmvcp.model.MyJavaBeanModel;

/**
 * This is the <i>view</i> of this application. </br></br>
 * 
 * It is a simple {@link JFrame JFrame} with a {@link JButton JButton}, a {@link JLabel JLabel} and a  {@link JTextArea JTextArea}</br></br>
 * 
 * When the button is clicked, it triggers an  {@link ActionEvent} which is being listened to by the  {@link MyController MyController} </br></br>
 * 
 * It is the default listener for event changes in the <i>model</i>, i.e. in the {@link MyJavaBeanModel MyJavaBeanModel} </br>
 * In particular, it listens for the "property change" event and it acts consequently. </br></br>
 * The label is updated every time a value in the <i>model</i> changes. </br>
 * More precisely, in this prototype, when {@link MyJavaBeanModel#myValueOne} is updated. </br>
 * This is done through the method {@link MyView#propertyChange(PropertyChangeEvent) propertyChange} in this class</br></br>
 * 
 * 
 * @author dsac
 */
@SuppressWarnings("serial")
public class MyView extends JFrame implements ActionListener, PropertyChangeListener{
	
	// this is the graphical element in which we will print some log messages
	private JTextArea logTextArea;
	private JButton updateOnceButton;
	private JToggleButton pollingButton;
	private JLabel javaBeanLabel;

	// the controller of the current view
	private MyController myController;
	// the model 
	private MyJavaBeanModel myJavaBeanModel;
	
	public MyView() {
		// Create and set up the main window by invoking the constructor of the "super" class, i.e. the JFrame
	    super("JavaJess MVC prototype");
	    super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	    super.setLayout(new BorderLayout());
	    
	    // create the children - 1: the update value button
	    updateOnceButton = new JButton("Update MyJavaBeanModel value");
	    pollingButton = new JToggleButton("Start/Stop Polling");
	    
	    // create the children - 2: the logArea
	    logTextArea = new JTextArea(20, 20);
	    logTextArea.setEditable(false); //only log messages, no user editing is possible
	    //logTextArea.setSize(500,250);
	    
	    // create the children - 3: the label
	    javaBeanLabel = new JLabel("Current JavaBean MyValueOne: " + (myJavaBeanModel==null ? "none" : myJavaBeanModel.getMyValueOne()));
	    
	    // create the children - 4: the textfield
	    
	    JPanel firstRowPanel = new JPanel(); // default layout: FlowLayout
	    firstRowPanel.add(javaBeanLabel);
	    firstRowPanel.add(updateOnceButton);
	    firstRowPanel.add(pollingButton);
	    
	    // add the children to the main frame
	    super.getContentPane().add(firstRowPanel, BorderLayout.PAGE_START);
	    //super.getContentPane().add(updateOnceButton, BorderLayout.PAGE_START);
	    super.getContentPane().add(new JScrollPane(logTextArea), BorderLayout.CENTER);
	
	    // Display the window.
	    super.pack();
	    super.setSize(750, 500);
	    super.setVisible(true);
	}
	
	
	/**
	 * It adds the controller to the current view. </br></br>
	 * 
	 * This is necessary because we need to link the user events (link the click on the {@link #updateOnceButton updateOnceButton})
	 * to the <i>controller</i> of this application, {@link MyController MyController}
	 * 
	 * @param myController the <i>controller</i> of this application, {@link MyController MyController}
	 */
	public void addController(MyController myController) 
	{
		this.addLogMessage("[View] - Adding controller");
		
		this.myController = myController;
		
		updateOnceButton.addActionListener(this.myController);
		pollingButton.addActionListener(this.myController);
		
		// I have also to listen to events on the update once button in the view because 
		// I will use this to release or not the start/stop button
		updateOnceButton.addActionListener(this);
	}
	
	/**
	 * Adds the model to this view.
	 * <p>
	 * The View will listen to event changes in the model and it will update automatically
	 * according to those changes.
	 * </p>
	 *
	 * @param myJavaBeanModel the model to be added to this view
	 */
	public void addModel(MyJavaBeanModel myJavaBeanModel) {
		if (this != null)
		{
			this.addLogMessage("[View] - Adding Model - that is, adding the MyJavaBeanModel");
		}
		this.myJavaBeanModel = myJavaBeanModel;
		// I add the property change listener here. The view will then get notified everytime
		// the model (myJavaBeanModel) will fire the property change event.
		this.myJavaBeanModel.addPropertyChangeListener(this);
	}
	
	/**
	 * It adds a simple log message to the frame.
	 * 
	 * @param logMessage
	 */
	public void addLogMessage(String logMessage)
	{
		// append the log Message and make sure that it shows to the user the bottom log messages
		// if the vertical scrolls appear
		logTextArea.append(logMessage + "\n");
		logTextArea.setCaretPosition(logTextArea.getDocument().getLength());
	}
	
	/**
	 * Detect the event change in the model (MyJavaBeanModel) and act consequently.
	 * <p>
	 * When this method will be called, the {@link #myJavaBeanModel} will have been updated by the 
	 * controller. Therefore, it will already contain the updated values of the <i> model</i>
	 * that the present <i>view</i> will properly render to the user.
	 * </p><p>
	 * In this prototype, the only thing we have to update is the {@link #javaBeanLabel} with the 
	 * updated values of the {@link #myJavaBeanModel}.
	 * </p>
	 * 
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
	 */
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if (this != null)
		{
			addLogMessage("      [View] - Model Event: PropertyChange - INIT");
			addLogMessage("      [View] - Model Event: detect change of the property - " + evt.getPropertyName() +": " +
					"newValue: + " + evt.getNewValue() + ", oldValue: " + evt.getOldValue() + ". ");
			addLogMessage("      [View] - Model Event: PropertyChange - I update the view...");
			
			// update the view with the new values
			javaBeanLabel.setText("Current JavaBean MyValueOne: " + (myJavaBeanModel==null ? "none" : myJavaBeanModel.getMyValueOne()));
			
			addLogMessage("      [View] - Model Event: PropertyChange - view has been updated...");
			addLogMessage("      [View] - Model Event: PropertyChange - END");
		}
	}



	/**
	 * A simple action to release the {@link #pollingButton} when the user presses the
	 * {@link #pollingButton}.
	 * <p>
	 * This way we avoid that the pollingButton remains pressed in case the user wants to 
	 * retrieve only one value from the service. By deselecting the pollingButton, we keep
	 * the view consistent.
	 * </p>
	 * <p>
	 * Please note how this code could have been place under the {@code MyController} as well. </br>
	 * However, we reckon the code to better follow the <i>MVCpattern</i> if everything related
	 * to the update of the view is actually kept in the view.  
	 * </p>
	 * 
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (pollingButton.isSelected())
		{
			pollingButton.setSelected(false);
		}
	}
	
	
}
